package org.project.d.network.handler;

import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.project.d.network.Dispatch;
import org.project.d.network.DispatchManager;
import org.project.d.network.ProfessionalWorkThreadFactory;
import org.project.d.network.exception.BusinessProcessingExceptionHandler;
import org.project.d.network.exception.BusinessProcessingExceptionHandlerManager;
import org.project.d.network.msg.Message;
import org.project.d.network.msg.Transmission;

import java.util.Collection;
import java.util.concurrent.*;

/**
 * @author lin
 * @version V1.0
 * @description
 * @date 2020/6/15 3:58 下午
 */
@ChannelHandler.Sharable
@Slf4j
public class MsgDispatcherHandler extends SimpleChannelInboundHandler<Message> {
    ExecutorService executor;

    public MsgDispatcherHandler() {
        int processors = Runtime.getRuntime().availableProcessors();
        executor= new ThreadPoolExecutor(processors,processors<<1,0,TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>(),new ProfessionalWorkThreadFactory("project-d-network"),(r,e)->log.error("task err poolInfo:{}",e));
    }

    public MsgDispatcherHandler(ExecutorService executor) {
        if (executor==null){
            throw new NullPointerException("executor must not null");
        }
        this.executor = executor;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception {
        // 分发消息器 根据消息类型进行分发处理
        if (msg.getMsgType()==null){
            log.error("unknown msg type please check cmd :{} packet: {}",msg.getMsgType(),msg.getPacket());
            return;
        }
        Dispatch dispatch = DispatchManager.getDispatch(msg.getMsgType().value());
        if (dispatch==null){
            log.error("unknown dispatch mapping msg type please check cmd :{} packet: {}",msg.getMsgType(),msg.getPacket());
            return;
        }
        MsgHandler msgHandler = dispatch.getMsgHandler();
        msg.decodeBody(dispatch.getMsgClass(),dispatch.getDeSerialized());
        executor.submit(()->{
            try {
                Transmission transmission = msgHandler.doHandler(msg);
                if (transmission!=null){
                    msg.getConnection().send(transmission);
                }
            } catch (Exception e) {
                Collection<BusinessProcessingExceptionHandler> businessProcessingExceptionHandlerMapping = BusinessProcessingExceptionHandlerManager.getBusinessProcessingExceptionHandler(msg.getMsgType().value());
                Collection<BusinessProcessingExceptionHandler> allBusinessProcessingExceptionHandler = BusinessProcessingExceptionHandlerManager.getBusinessProcessingExceptionHandler(null);
                if (businessProcessingExceptionHandlerMapping.size()<1||allBusinessProcessingExceptionHandler.size()<1){
                    log.error("execute err ",e);
                    return;
                }
                for (BusinessProcessingExceptionHandler businessProcessingExceptionHandler : businessProcessingExceptionHandlerMapping) {
                    log.info("have BusinessProcessingException run businessProcessingExceptionHandler");
                    businessProcessingExceptionHandler.hadnler(msgHandler,msg,e);
                }
                for (BusinessProcessingExceptionHandler businessProcessingExceptionHandler : allBusinessProcessingExceptionHandler) {
                    log.info("have BusinessProcessingException run businessProcessingExceptionHandler");
                    businessProcessingExceptionHandler.hadnler(msgHandler,msg,e);
                }
            }
        });
    }
}
